#include "Platform.hpp"
#include "error/Exception.hpp"
#include "GLLibs.hpp"
using namespace klas;


#include <iostream>
using namespace std;














#include "graphics/RenderingCore.hpp"
#include "graphics/Texture.hpp"
#include "graphics/Renderable.hpp"
#include "Engine.hpp"
#include "graphics/Sprite.hpp"
#include "graphics/Primitive.hpp"
#include "graphics/Text.hpp"

#include "graphics/gl/GLRenderingCore.hpp"
#include "graphics/gl/GLFont.hpp"
#include "tools/Timer.hpp"
#include "tools/General.hpp"

#include "graphics/gl/GLShaderProgram.hpp"
#include "graphics/gl/GLShader.hpp"

#include "graphics/gl/GLRenderToTexture.hpp"

#include "graphics/PostProcessor.hpp"

int main(int argc, char* args[])
{
  try {

    Engine::init(library::GL, math::Vector2<int>(1000, 800), "klas engine", graphics::colors::Teal, false);

    graphics::Texture* tex = Engine::newTexture("test.png");
    graphics::Font* font = new graphics::gl::GLFont("Malgecito.ttf", 72);


    graphics::Text text("klas engine says hi", font);
    text.setPos(600, 100);
    text.setColor(graphics::colors::HotPink);


    //data::Manager* dataManager = new dataManager();
    //dataManager->loadResources("filename.klas");

    //graphics::Texture* tex = dataManager->generateTexture("hello");
    //graphics::Texture* tex2 = dataManager->get("sup");

    graphics::Sprite sprite(tex, graphics::Transformation(math::Vector2d(300, 600), math::Vector2d(60, 60), 0), graphics::colors::White);

    graphics::Primitive prim;
    prim.setShape(graphics::primitiveTypes::CIRCLE);
    
    prim.setTransformation(     graphics::Transformation( math::Vector2d(200, 100),
                                math::Vector2d(85, 55),
                                0) );

    graphics::Primitive prim2;
    prim2.setShape(graphics::primitiveTypes::RECTANGLE);
    prim2.setColor(graphics::colors::HotPink);
    prim2.setSize(math::Vector2d(20, 50));
    prim2.setPos(400, 300);
    //prim2.setPolygonMode(graphics::primitiveTypes::WIREFRAME);


    graphics::Primitive triangle;
    triangle.setShape(graphics::primitiveTypes::TRIANGLE, 1);
    triangle.setSize(50, 50);
    triangle.setPos(650, 500);
    triangle.setColor(graphics::colors::DarkGoldenrod);

    graphics::Primitive parent;
    parent.setColor(graphics::Color(0.0, 0.0, 0.0, 0.0));

    
    //parent.addChild(&prim);
    //parent.addChild(&prim2);
    //parent.addChild(&text);
    //parent.addChild(&triangle);
    //parent.addChild(&sprite);

    double reverseX = 1, reverseY = -1;

    SDL_Event* event = new SDL_Event();
    klas::tools::Timer time, trigTime;
    uint32 frames = 0;

    graphics::ShaderProgram* program = new graphics::gl::GLShaderProgram();
    graphics::Shader* vert = new graphics::gl::GLShader("test.vert", graphics::Shader::VERTEX_SHADER);
    graphics::Shader* frag = new graphics::gl::GLShader("test.frag", graphics::Shader::FRAGMENT_SHADER);
    
    graphics::gl::GLRenderToTexture renderToTex(math::Vector2<uint32>(1000, 800));
    graphics::gl::GLRenderToTexture renderToTex2(math::Vector2<uint32>(1000, 800));

    program->attach(vert);
    program->attach(frag);
    program->link();
    program->enable();
    program->setVariable("klas_color", .7, .3, .3, 1.0);
    program->disable();

    graphics::Shader* sinVert = new graphics::gl::GLShader("sin.vert", graphics::Shader::VERTEX_SHADER);
    graphics::ShaderProgram* sinProgram = new graphics::gl::GLShaderProgram();
    sinProgram->attach(sinVert);
    sinProgram->link();


    graphics::PostProcessor post(math::Vector2<uint32>(1000, 800));
    graphics::PostProcessorBatch postBatch;
    postBatch.addEffect(sinProgram);//postBatch.addEffect(program);
    
    //postBatch.addEffect(program);
    //postBatch.addEffect(program);
    //postBatch.addEffect(program);
    //postBatch.addEffect(program);
    post.addBatch(postBatch, math::Vector2d(1, 1));
    //post.addBatch(postBatch, math::Vector2d(50, 50));
    //post.addBatch(postBatch, math::Vector2d(50, 50));

    

    GLfloat texCoordOffsets[18];
    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            float xInc = 1.0f / (GLfloat)1000; // fbo width
            float yInc = 1.0f / (GLfloat)800; //fbo height
            texCoordOffsets[(((i*3)+j)*2)+0] = (-1.0f * xInc) + ((GLfloat)i * xInc);
            texCoordOffsets[(((i*3)+j)*2)+1] = (-1.0f * yInc) + ((GLfloat)j * yInc);
        }
    }
    
    program->enable();
    program->setVariable("tc_offset", 2, 9, reinterpret_cast<double*>(texCoordOffsets));
    program->disable();

    int timeID = program->getID("time");
    int modifierID = program->getID("modifier");
    bool run = true; double modifier = 0.0, changeDirectionModifier = 1;
    while(run)
    {
      ++frames;
      if(time.getSeconds() > 1.0)
      {
        text.setText(string("fps: ") + tools::General::toString(int(frames / time.getSeconds())));
        time.restart();
        frames = 0;
      }

      program->enable();
      program->setVariable(timeID, trigTime.getSeconds());
      program->setVariable(modifierID, modifier);
      program->disable();

      sinProgram->enable();
      sinProgram->setVariable("time", trigTime.getSeconds());
      sinProgram->setVariable("modifier", modifier);
      sinProgram->disable();

      modifier += .03 * changeDirectionModifier;

      if(modifier > 1.0)
      {
        modifier = .99;
        changeDirectionModifier = -1;
      }
      if(modifier < 0.0)
      {
        modifier = .01;
        changeDirectionModifier = 1;
      }

      while(SDL_PollEvent(event))
      {
        if(event->type == SDL_QUIT)
          run = false;


        if((event->type == SDL_KEYDOWN) && (event->key.keysym.sym == SDLK_UP))
          parent.setTransparency(parent.getTransparency() + .03);

        if((event->type == SDL_KEYDOWN) && (event->key.keysym.sym == SDLK_DOWN))
          parent.setTransparency(parent.getTransparency() - .03);
      }
        
        //sprite.setRot(sprite.getRot() + .01);

        if(prim2.getSizeY() > 700 || prim2.getSizeY() < -500)
          reverseY *= -1;

        //if(sprite.getSizeX() > 20 || sprite.getSizeX() < -8)
        //  reverseX *= -1;

        if(triangle.getShape().angle >= 180)
          reverseX = -1;
        if(triangle.getShape().angle <= 0)
          reverseX = 1;


        //sprite.setSizeY(prim.getSizeY() + reverseY * .005);
        //sprite.setSizeX(prim.getSizeX() + reverseX * .01);
        //sprite.setSize(sprite.getSizeX() - 2, sprite.getSizeY() - .035);
        //sprite.setSize(64, 64);
        //prim.setRot(prim.getRot() + .01);
        //prim.setSize(prim.getSizeX() + .005, prim.getSizeY() + .007);
        prim2.setRot(prim2.getRot() - 2 * reverseY);
        prim2.setSizeY(prim2.getSizeY() + reverseY * .1);
        //text.setRot(text.getRot() + .08);
   
        triangle.setShape(triangle.getShape().primitiveType, triangle.getShape().angle + (.022 * reverseX));

          

        prim.render(Engine::renderingCore);


        

        post.startedRendering();
        glClear(GL_COLOR_BUFFER_BIT);
        Engine::render(math::Rectd(0, 0, 1000, 800));
        post.finishedRendering();
        post.render();


        sprite.render(Engine::renderingCore);
        text.render(Engine::renderingCore);
        Engine::render(math::Rectd(0, 0, 1000, 800));
        
        
      
       


      SDL_GL_SwapBuffers();
      glClear(GL_COLOR_BUFFER_BIT);
    }
  }
  catch(error::Exception& e) {
    cout << e.what() << endl;
    system("PAUSE");
  }

  

  return 0;
}